package org.csu.softwaremetrics_demo.metric.lk;

import org.csu.softwaremetrics_demo.entity.common.LKMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.result.Result;
import org.csu.softwaremetrics_demo.metric.Metric;
import org.eclipse.jdt.core.dom.*;

/**
 * @Description:
 * @Author: Jukomu
 * @Package: org.csu.softwaremetrics_demo.metric.lk
 * @Project: SoftwareMetrics_demo
 * @name: NOO
 * @Date: 2025/4/6-19:54
 * @Filename: NOO
 */
public class NOO extends ASTVisitor implements Metric<LKMetricSingleClass> {
    /**
     * 存储方法计数的字段
     */
    private int method_overwrite;

    /**
     * 访问类型声明节点
     *
     * @param node 类型声明节点
     * @return 如果是接口则返回false，否则返回true
     */
    @Override
    public boolean visit(TypeDeclaration node) {
        // 遇到接口直接返回
        if (node.isInterface()) {
            return false;
        }

        // 获取类型绑定 null -> 无法获取有效的类型 -> 存在错误拼写或动态类型
        ITypeBinding binding = node.resolveBinding();
        if (binding != null) {
            // 获取类型声明中的所有方法
            MethodDeclaration[] methods = node.getMethods();

            // 遍历所有方法
            for (MethodDeclaration method : methods) {
                // 获取方法的绑定
                IMethodBinding methodBinding = method.resolveBinding();
                // 如果方法绑定不为空且方法是重写的方法
                if (methodBinding != null && isOverriddenMethod(methodBinding)) {
                    // 方法重写计数器加1
                    method_overwrite++;
                }
            }
        }
        // 返回false表示继续访问子节点
        return false;
    }

    /**
     * 执行方法，接受编译单元并计算指标
     *
     * @param cu           编译单元
     * @param singleMetric 单类指标
     * @param result       结果
     */
    @Override
    public void execute(CompilationUnit cu, LKMetricSingleClass singleMetric, Result result) {
        cu.accept(this);
    }

    /**
     * 设置单类指标
     *
     * @param singleMetric 单类指标
     */
    @Override
    public void setSingleMetric(LKMetricSingleClass singleMetric) {
        singleMetric.setNoo(method_overwrite);
    }

    /**
     * 判断方法是否被重写
     *
     * @param method 方法绑定
     * @return 如果方法被重写则返回true，否则返回false
     */
    private boolean isOverriddenMethod(IMethodBinding method) {
        ITypeBinding declaringClass = method.getDeclaringClass();
        ITypeBinding superclass = declaringClass.getSuperclass();

        while (superclass != null) {
            for (IMethodBinding superMethod : superclass.getDeclaredMethods()) {
                if (method.overrides(superMethod)) {
                    return true;
                }
            }
            superclass = superclass.getSuperclass();
        }
        return false;
    }
}
